package org.TCC_NOVO.dao;


import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;

public final class JPAUtil 
{	
	private static JPAUtil jpa;
	private static final String mensagem = "Faltou iniciar a classe. Execute JPAUtil.inicializar() passando o nome da unidade de persistencia.";	
	
	private EntityManager gerenciadorEntidade;	
	private EntityManagerFactory fabricaGerenciadorEntidade;
	
	
	public static void inicializar(String nomeUnidadePersistencia) throws Exception 
	{
		if (jpa != null) 
			return;
		
		jpa = new JPAUtil(nomeUnidadePersistencia);
		
	}
	
	public static JPAUtil getInstance() throws Exception 
	{
		if (jpa == null) throw new Exception(mensagem);
		
		return jpa;
	}

	public static void finalizar() 
	{
		jpa.fechar();
		jpa.fabricaGerenciadorEntidade.close();
		jpa = null;
	}

	private JPAUtil(String persistenceUnitName) 
	{
		try
		{
			fabricaGerenciadorEntidade = Persistence.createEntityManagerFactory(persistenceUnitName);
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
	
	public void incluir(Object obj) 
	{
		EntityManager em = getGerenciadorEntidade();
		em.getTransaction().begin();
		em.persist(obj);
		em.getTransaction().commit();
	}

	public void alterar(Object objeto) 
	{
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();
		gerenciadorEntidade.getTransaction().begin();
		gerenciadorEntidade.merge(objeto);
		gerenciadorEntidade.getTransaction().commit();
		
	}

	@SuppressWarnings("unchecked")
	public <T> T ler(Class<T> classe, Object id) 
	{
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();
		Object objeto = gerenciadorEntidade.find(classe, id);
		
		return (T) objeto;
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> listarTodos(Class<T> classe) 
	{		
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();
		Query consulta = gerenciadorEntidade.createQuery("select x from " + classe.getSimpleName() + " as x");
		List<T> resultado = consulta.getResultList();
		
		return resultado;
	}
	
	public void excluir(Object objeto)
	{
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();
		gerenciadorEntidade.getTransaction().begin();
		gerenciadorEntidade.remove(objeto);
		gerenciadorEntidade.getTransaction().commit();
	}
		
	@SuppressWarnings("unchecked")
	public <T> T consultaNomeada(String consultaNomeada, Map<String, Object> parametros)
	{
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();
		Query consulta = gerenciadorEntidade.createNamedQuery(consultaNomeada);
		
		if (parametros != null)
		{
			Set<String> nomesParametros = parametros.keySet();
			
			for (String nomeParametro: nomesParametros)
				consulta.setParameter(nomeParametro, parametros.get(nomeParametro));
		}

		try 
		{ 
			return (T) consulta.getSingleResult(); 
		}
		catch (NoResultException e) 
		{ 
			return null; 
		}
	}
	
	public final Object executarConsulta(String sql, long registroInicial, long registroFinal, Map<String, Object> parametros)
	{
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();
		Query consulta = gerenciadorEntidade.createQuery(sql);
		
		if (parametros != null)
		{
			Set<String> nomesParametros = parametros.keySet();
			
			for (String nomeParametro: nomesParametros)
			{
				try { consulta.setParameter(nomeParametro, parametros.get(nomeParametro)); }
				catch (Exception e) { System.out.println("Parametro '" + nomeParametro + "' n�o existe!"); }
			}
		}
		
		if ((registroInicial >= 0) && (registroFinal > registroInicial))
		{
			consulta.setFirstResult((int) registroInicial);
			consulta.setMaxResults((int) (registroFinal - registroInicial));
		}
			
		return consulta.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public <T> List<T> listarConsultaNomeada(String nome, long registroInicial, long registroFinal, Map<String, Object> parametros)
	{
		EntityManager gerenciadorEntidade = getGerenciadorEntidade();		
		Query consulta = gerenciadorEntidade.createNamedQuery(nome);

		if ((parametros != null) && (parametros.size() > 0))
		{
			Set<String> nomesParametros = parametros.keySet();
			
			for (String nomeParametro: nomesParametros)
			{
				try { consulta.setParameter(nomeParametro, parametros.get(nomeParametro)); }
				catch (Exception e) { System.out.println("Parametro '" + nomeParametro + "' n�o existe!"); }
			}
		}
		
		if ((registroInicial >= 0) && (registroFinal > registroInicial))
		{
			consulta.setFirstResult((int) registroInicial);
			consulta.setMaxResults((int) (registroFinal - registroInicial));
		}
		
		return consulta.getResultList();
	}
	
	public EntityManager getGerenciadorEntidade() 
	{
		if (gerenciadorEntidade == null) gerenciadorEntidade = fabricaGerenciadorEntidade.createEntityManager();
		
		return gerenciadorEntidade;
	}
	
	public void fechar() 
	{
		if (gerenciadorEntidade != null) 
		{
			gerenciadorEntidade.close();
			gerenciadorEntidade = null;
		}
	}
	
	
}
